package cmap

import (
	"sync"
	"sync/atomic"
)

type Segment interface {
	Set(item Item)(bool,error)
	Get(key string)Item
	Delete(key string)bool
	Size()uint64
}
type mySegment struct {
	size uint64
	buckets []Bucket
	locker sync.RWMutex
	bucketNum int
	maxBucketSize uint64
	rdb Redistribute
	minBucketNum int
}
func(this *mySegment)Get(key string)Item{
	hash := hash(key)
	this.locker.RLock()
	bucket := this.buckets[hash%uint64(this.bucketNum)]
	this.locker.RUnlock()
	return  bucket.Get(key)
}
func (this *mySegment)Set(item Item)(bool,error)  {
	this.locker.Lock()
	defer this.locker.Unlock()


	bucket := this.buckets[item.Hash()%uint64(this.bucketNum)]
	ok ,err := bucket.Set(item)
	if ok{
		newtotal := atomic.AddUint64(&this.size,1)
		this.redistribute(newtotal,bucket.Size())
	}
	return ok,err
}
func (this *mySegment)Delete(key string)bool  {
	this.locker.Lock()
	defer this.locker.Unlock()
	hash := hash(key)
	bucket := this.buckets[hash%uint64(this.bucketNum)]
	ok := bucket.Delete(key)
	if ok{
		newtotal := atomic.AddUint64(&this.size,^uint64(0))
		this.redistribute(newtotal,bucket.Size())
	}
	return ok
}
func (this *mySegment)Size()uint64  {
	return atomic.LoadUint64(&this.size)
}
func (this *mySegment)redistribute(total uint64,bucketSize uint64) error{
	this.rdb.UpdateThreshold(total,this.bucketNum)
	status := this.rdb.CheckBucketStatus(bucketSize)
	newBuckets,chanage := this.rdb.Redistribe(status,this.buckets)
	if chanage{
		this.buckets = newBuckets
		this.bucketNum = len(newBuckets)
	}
	return nil
}
func NewSegment(minBucketNum int,maxBucketSize uint64)( Segment,error)  {
	 segment := &mySegment{
	 	minBucketNum:minBucketNum,
	 	maxBucketSize:maxBucketSize,
	 	bucketNum:minBucketNum,
	 }
	 var err error
	segment.rdb,err = NewRedistribute(float64(0.75),maxBucketSize,minBucketNum)
	if err != nil{
		return nil,err
	}
	buckets := make([]Bucket,minBucketNum)
	for i:=0;i<minBucketNum;i++{
		buckets[i] = NewBucket()
	}
	segment.buckets = buckets
	return segment,nil
}